import {
  ActionIcon,
  Group,
  Modal,
  Table,
  Box,
  TextInput,
  Button,
  ModalProps,
  MantineProvider,
  Paper,
  Space,
  Popover
} from '@mantine/core'
import { useState } from 'react'
import { Edit as EditIcon, Trash as TrashIcon } from 'tabler-icons-react'
import { useForm } from '@mantine/form'
import { NotificationsProvider, showNotification } from '@mantine/notifications'
import useSWR, { useSWRConfig } from 'swr'

let _ = await import(
  /* @vite-ignore */ `https://lib.localhost/iframe.mjs` as string
)
const { Command } = _.shell

const FORM_WIDTH = 280

function getInfo(output: string) {
  let flag = false
  let data = []
  for (let row of output.split(/\n+/)) {
    console.log('row:', row)
    const [srcAddress, srcPort, dstAddress, dstPort] = row
      .split(/ +/)
      .map(s => s.trim())
    if (srcAddress.startsWith('-') && srcPort.startsWith('-')) {
      flag = true
      continue
    }
    if (flag && srcAddress) {
      data.push({
        srcAddress,
        srcPort,
        dstAddress,
        dstPort
      })
    }
  }
  return data
}

const addPortProxy = async (data: RecordType) => {
  let { srcAddress, dstAddress, srcPort, dstPort } = data
  const cmd = `chcp 65001 & netsh interface portproxy add v4tov4 listenport=${srcPort} listenaddress=${srcAddress} connectaddress=${dstAddress} connectport=${dstPort}`
  return await new Command('cmd', ['/C', cmd]).execute()
}

const delPortProxy = async (data: RecordType) => {
  let { srcAddress, srcPort } = data
  const cmd = `chcp 65001 & netsh interface portproxy delete v4tov4 listenport=${srcPort} listenaddress=${srcAddress}`
  return await new Command('cmd', ['/C', cmd]).execute()
}

type RecordType = {
  srcAddress: string
  srcPort: string
  dstAddress: string
  dstPort: string
}

interface ModalFormProps extends ModalProps {
  data: RecordType
}

interface PortProxyEditFormProps {
  initialValues: RecordType
  onSubmit(values: RecordType): void
  onCancel(): void
}

const INITIALVALUES: RecordType = {
  srcAddress: '*',
  srcPort: '',
  dstAddress: '',
  dstPort: ''
}

const query = async () => {
  const res = await new Command('cmd', [
    '/C',
    'chcp 65001 & netsh interface portproxy show all'
  ]).execute()
  return getInfo(res?.stdout ?? '')
}

const add = async (values: RecordType) => {
  try {
    const addRes = await addPortProxy(values)
    console.log(addRes)
    const message = addRes?.stdout.replace('Active code page: 65001', '').trim()
    if (message) {
      showNotification({
        color: 'red',
        message
      })
    }
  } catch (error) {
    console.log(error)
  }
}

const edit = async (oldValues: RecordType, newValues: RecordType) => {
  try {
    const delRes = await delPortProxy(oldValues)
    const addRes = await addPortProxy(newValues)
    console.log(addRes)
    const message = addRes?.stdout.replace('Active code page: 65001', '').trim()
    if (message) {
      showNotification({
        color: 'red',
        message
      })
    }
  } catch (error) {
    console.log(error)
  }
}

function PortProxyEditForm({
  initialValues,
  onSubmit
}: PortProxyEditFormProps) {
  const form = useForm<RecordType>({
    initialValues,
    validate: values => ({
      name: values.srcAddress.length > 15 ? 'Too long address' : null,
      srcPort: values.srcPort === undefined ? 'Port is required' : null
    })
  })
  return (
    <form onSubmit={form.onSubmit(onSubmit)}>
      <TextInput
        label='侦听地址'
        placeholder='*'
        size='xs'
        {...form.getInputProps('srcAddress')}
      />
      <TextInput
        label='侦听端口'
        placeholder='5432'
        size='xs'
        {...form.getInputProps('srcPort')}
      />
      <TextInput
        label='连接地址'
        placeholder='9.172.7.2'
        size='xs'
        {...form.getInputProps('dstAddress')}
      />
      <TextInput
        label='连接端口'
        placeholder='5432'
        size='xs'
        {...form.getInputProps('dstPort')}
      />

      <Group position='right' mt='xs'>
        <Button type='submit' size='xs'>
          提交
        </Button>
      </Group>
    </form>
  )
}

function ModalForm({ data, onClose, opened }: ModalFormProps) {
  const { mutate } = useSWRConfig()
  return (
    <Modal
      size={FORM_WIDTH}
      overlayOpacity={0}
      opened={opened}
      onClose={onClose}
      padding='sm'
      title='新增'
      shadow='xs'
    >
      <Box sx={{ maxWidth: FORM_WIDTH }} mx='auto'>
        <PortProxyEditForm
          initialValues={data ?? INITIALVALUES}
          onCancel={() => onClose()}
          onSubmit={async values => {
            await add(values)
            mutate('query')
            onClose()
          }}
        />
      </Box>
    </Modal>
  )
}

function EditPortProxyPopover({ data: initialValues }: { data: RecordType }) {
  const [opened, setOpened] = useState(false)
  const { mutate } = useSWRConfig()
  return (
    <Popover
      opened={opened}
      onClose={() => setOpened(false)}
      withCloseButton
      title='编辑'
      width={FORM_WIDTH}
      transition='pop-top-right'
      target={
        <ActionIcon onClick={() => setOpened(o => !o)}>
          <EditIcon size={14} />
        </ActionIcon>
      }
    >
      <PortProxyEditForm
        initialValues={initialValues}
        onCancel={() => setOpened(false)}
        onSubmit={async data => {
          await edit(initialValues, data)
          mutate('query')
          setOpened(false)
        }}
      />
    </Popover>
  )
}

function App() {
  const [opened, setOpened] = useState(false)
  const { data, mutate, error } = useSWR('query', query)

  const rows = data?.map((row: RecordType, i) => (
    <tr key={i}>
      <td>{row.srcAddress}</td>
      <td>{row.srcPort}</td>
      <td>{row.dstAddress}</td>
      <td>{row.dstPort}</td>
      <td>
        <Group
          position='center'
          spacing='xs'
          sx={theme => ({
            gap: 5
          })}
        >
          <EditPortProxyPopover data={row} />
          <ActionIcon
            variant='hover'
            onClick={() => {
              delPortProxy(row)
                .then(res => {
                  console.log('delete portproxy:', res)
                  const message = res?.stdout
                    .replace('Active code page: 65001', '')
                    .trim()
                  if (message) {
                    showNotification({
                      color: 'red',
                      message
                    })
                  } else {
                    showNotification({
                      message: '删除成功'
                    })
                  }
                })
                .finally(() => mutate())
            }}
          >
            <TrashIcon size={14} />
          </ActionIcon>
        </Group>
      </td>
    </tr>
  ))
  return (
    <MantineProvider>
      <NotificationsProvider>
        <Paper>
          <Group position='right' spacing='xs'>
            <Button size='xs' onClick={() => setOpened(true)}>
              新增
            </Button>
          </Group>
          <Space h='xs' />
          <Paper p='xs' withBorder>
            <Table
              sx={{
                '& > thead > tr > th:last-child': {
                  textAlign: 'center'
                },
                '& > tbody > tr > td:last-child': {
                  textAlign: 'center'
                }
              }}
            >
              <thead>
                <tr>
                  <th>侦听地址</th>
                  <th>侦听端口</th>
                  <th>连接地址</th>
                  <th>连接端口</th>
                  <th>操作</th>
                </tr>
              </thead>
              <tbody>{rows}</tbody>
            </Table>
            <ModalForm
              data={INITIALVALUES}
              opened={opened}
              onClose={() => {
                setOpened(false)
              }}
            />
          </Paper>
        </Paper>
      </NotificationsProvider>
    </MantineProvider>
  )
}

export default App
